#pragma once
#ifndef OPTDATA_H
#define OPTDATA_H

#include <iostream>
#include <fstream>
#include <vector>
#include "Structure.h"
#include "stdexcept"
#include <boost/filesystem.hpp>
#include <boost/algorithm/string.hpp>
#include <string>
#include <sstream>
#include <math.h>


using namespace std;
using namespace boost::filesystem;


struct SDij 
{
	int nPoint;           //1D position 
	int nFieldID;      //field name for which field is
	int nBeamletID;       //beamlet ID for which beamlet is    
	double nContribution;  //the beamlet contribution for this point 
};

typedef struct  
{
	int64_t m_nID;
	float m_fContrib;
}INFLU_ELEM;

struct RadiationObj 
{
	string strStructureName;
	double aimDose;
	double aimWeight;
	string constraintType;	//uniform, upper, lower, EUD
};

class OptData
{
public:
	/***************         constructor and destructor            ***************/
	OptData(void);
	OptData(const OptData &obj);
	~OptData();

	OptData& operator = (OptData& obj);

	/***************            getter and setter                  ***************/
	void setDoseMatrixSize(unsigned int x, unsigned int y, unsigned int z)
	{
		this->m_nSizeX = x;
		this->m_nSizeY = y;
		this->m_nSizeZ = z;
	}
	void getDoseMatrixSize(unsigned int &x, unsigned int &y, unsigned int &z)
	{
		x = this->m_nSizeX;
		y = this->m_nSizeY;
		z = this->m_nSizeZ;
	}

	unsigned int getBeamletNumTotal(void)
	{return this->m_nBeamletNumTotal;}

	vector<int> getFieldBeamletNum(void)
	{ return this->m_vFieldBeamletNum;}

	void addStructure(Structure structure)
	{
		this->m_vStructures.push_back(structure);
	}
	vector<Structure>* getStructures(void)
	{
		return &this->m_vStructures;
	}
	vector<vector<double> >* getDijTotal(void)
	{return &this->m_vDijTotal;}
	vector<double>* getWeightTotal(void)
	{return &this->m_vWeightTotal;}
	void setWeightTotal(vector<double> weights){
		this->m_vWeightTotal = weights;
	}

	//store dose 
	vector<double>* getDose(void){
		return &this->m_vDose;
	}

	//store EUD
	vector<double>* getEUD(void){
		return &this->m_vEUD;
	}

	vector<RadiationObj>* getObjectives(void){
		return &this->m_vObjs;
	}

	vector<double>* getObjFunValues(void){
		return &this->m_vObjFunValues;
	}

	//void addField(CFieldDose &field);
	//return z * m_nSizeY * m_nSizeX + y* m_nSizeX + x;
	unsigned int position3DTo1D(unsigned int x, unsigned int y, unsigned int z)
	{
		return z*(this->m_nSizeY)*(this->m_nSizeX) + y*(this->m_nSizeX) + x;
	};

	/***************            calculate dose                      ***************/
	//vector<double> calculateDose(vector<double> *vWeight); 
	bool calculateDose(void);
	vector<double>  calculateDVH(Structure structure, double dvhResolution=0.01);
	//based on m_vDose and m_vStructures calculate EUD
	bool calculateEUD(void);

	bool inputDoseSize(string inDoseSizePath);
	bool inputBeamType1(int fieldID, string inDijPath, string inSpotWeightPath);	//first line dosegride size 100,69,84 others 40,25,10,1298,2.46423e-009
	bool inputBeamType2(int fieldID, string inDijPath, string inSpotWeightPath);	//no first line dosegride 9.0.1.0.317 0.0381065
	bool inputBeam(int fieldID, string inDijPath, string inSpotWeightPath);
	bool inputBeamFromBin(int fieldID, string inDijPath, string inSpotWeightPath);
	bool inputStructure(string structName, string inStructPath,double EUD);
	bool inputObjective(string objString);		//PTV,uniform,76,200
	bool inputDose(string inDosePath);


	//void outputWeight(map<int,double> *mWeight, string outWeightPath);
	bool outputWeight(string outputDir);
	bool outputDij(string outputDir);
	bool outputDose(string outputDir);
	bool outputObjValue(string outputDir);
	bool outputDVH(string outputDir, double dvhResolution=0.01);

private:
	/***************    store data which read from files            ***************/
	//store dose matrix size which read from dosegrid file
	unsigned int m_nSizeX; 
	unsigned int m_nSizeY;
	unsigned int m_nSizeZ; 

	unsigned int m_nBeamletNumTotal;
	vector<int> m_vFieldBeamletNum;
	//unsigned int m_nWeightNumTotal;

	//store structure data which read from structure files
	vector<Structure> m_vStructures;

	//store field data which read from SpotField_#.ca files
	vector<int>  m_vDijIndex;
	vector<vector<double> > m_vDijTotal;    //row * line = point * beamlet(weight number)

	//store field data which read from SpotWeightO_#.txt files   
	vector<double> m_vWeightTotal;

	//store dose 
	vector<double> m_vDose;

	//store EUD
	vector<double> m_vEUD;

	//store objectives
	vector<RadiationObj> m_vObjs;

	vector<double> m_vObjFunValues;
};

#endif